package com.xiao.code.parse;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;

import japa.parser.JavaParser;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.ImportDeclaration;
import japa.parser.ast.Node;
import japa.parser.ast.PackageDeclaration;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.body.VariableDeclarator;
import japa.parser.ast.comments.LineComment;
import japa.parser.ast.expr.AnnotationExpr;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.expr.ObjectCreationExpr;
import japa.parser.ast.expr.StringLiteralExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;
import japa.parser.ast.stmt.BlockStmt;
import japa.parser.ast.stmt.ExpressionStmt;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.visitor.GenericVisitor;
import japa.parser.ast.visitor.VoidVisitor;
import japa.parser.ast.visitor.VoidVisitorAdapter;

public class TestParse {
	
  public static JavaDescribe  javaDescribe = new JavaDescribe();

	public static void main(String[] args)throws Exception {
		
		 // creates an input stream for the file to be parsed

        CompilationUnit serviceJava;
        
        javaDescribe.file = new File("E:\\lyf\\codetest\\reso\\Test.java");
        
        try {
            // parse the file
        	serviceJava = javaDescribe.getJavaParser() ;
        } finally {
        }
        javaDescribe.rpImp("com.odianyun.architecture.caddy.SystemContext", "com.odianyun.architfsdfasdafxt");
        
        javaDescribe.addImpl(new HashSet<>(Arrays.asList("xiaoa","xiaoa")));
        
//        
//        serviceJava.setPackage(new PackageDeclaration(new NameExpr("com.xiaoa")));
        
//        serviceJava.getImports().forEach(e -> System.out.println(((ImportDeclaration)e).getName()));
        
//        find(serviceJava, LineComment.class).stream().filter(e -> e.toString().contains("daima"))
//                                               .forEach(e -> {
//                                            	    System.out.println(e.getClass() + ":" + e);
//                                            	    
//                                               });
        
        
        
        
//        find(serviceJava, Node.class).
//        stream().filter(e -> e.toString().contains("daima"))
//             .forEach(e -> System.out.printf(e.getClass() + ":" + e));
//        .collect(Collectors.toList()).get(0)
//        .setContent("dadad");
        

        // visit and print the methods names
//        new MethodVisitor().visit(serviceJava, null);
//        
//        serviceJava.getImports().forEach(e -> {
//        	
//        	
//        	System.out.println(e);
//        });
//        

        
        System.out.println(serviceJava);

	}
	 public static List<ExpressionStmt> findNodeByBlock(Node parse , String name){
			
			List<ExpressionStmt>  list =  find(parse,ExpressionStmt.class).stream()
	    			                                         // 寻找代码块
	    			                                         .filter(node -> node.toString().contains(name))
	    			                                         .collect(Collectors.toList());
	    	
		    return list;
		}
		

	 
	 public static <T> List<T> find(Node parse ,Class<T>  cla, String name){
			
			List<T>  list =  find(parse,cla).stream()
	    			                                         // 寻找代码块
	    			                                         .filter(node -> node.toString().contains(name))
	    			                                         .collect(Collectors.toList());
	    	
		    return list;
		}
		

	  public static <T> List<T> find(Node node , Class<T> cla){
	  	
	  	List<T>  list = new ArrayList<>();

	  	if (node.getClass().equals(cla)){
	  		list.add((T)node);
	  	}else {
	  		node.getChildrenNodes().forEach(e -> list.addAll(find(e,cla)));
	  	}
	  	
	  	return list;
	  	
	  }
	  

	 
	  /**
     * Simple visitor implementation for visiting MethodDeclaration nodes. 
     */
    private static class MethodVisitor extends VoidVisitorAdapter {

        @Override
        public void visit(MethodDeclaration n, Object arg) {
            // here you can access the attributes of the method.
            // this method will be called for all methods in this 
            // CompilationUnit, including inner class methods
        	
        	javaDescribe.findBlockByVal(n, "client").forEach(e -> {
        		// 代码块
				String bStr = e.toString(); 
				String[] bs = bStr.split("=");
				
				String[] csp = bs[1].split("\\.");
				
    			String methodName = csp[1].substring(0, csp[1].indexOf("(")).trim();
    			
    			String orgName =  csp[1].substring(csp[1].indexOf("(")+1, csp[1].lastIndexOf(")")).trim();

        		// 获取返回类型
        		String strType = bs[0].split(" ")[0].trim();
        		
        		System.out.println(e);
        		// 寻找类型
        		Set<String> implSet = javaDescribe.doFindImpl(e).stream()
                        .collect(Collectors.toSet());  
        		
        		System.out.println(JSON.toJSONString(implSet));
        		System.out.println("aa");
        	});
        	
        	
        	
//        	Start.find(n, MethodCallExpr.class).forEach(System.out::println);
        	
//        	n.setName("hhh");
//        	
//        	
//        	// 获取代码块
//        	Node node  = n.getChildrenNodes().stream().filter(e -> e instanceof BlockStmt).collect(Collectors.toList()).get(0);
//        
//        	// 获取有关Client.getInstanst 接口实现的代码块
//        	List<Node> clientNodeList = node.getChildrenNodes().stream().filter(e -> {
//					        		String str = e.toString();
//					        		if (str.contains("list")
//					        				){
//					        			return true;
//					        		}
//					        		return false;
//					        	}).filter(e -> e instanceof ExpressionStmt)
//        			              .collect(Collectors.toList());
//        	
//        	for (Node valClintNode : clientNodeList){
//        		
//        		String str = valClintNode.toString();
//        		String oi = str.split("=")[1];
//        		String[] os = oi.split("\\.");
//        		String claName = null;
//        		String mName = null;
//        		String orgName = null;
//        		
//        		Set<String> implSet = new HashSet<>();
//        		// 如果是 
//        		if (os.length > 2){
//        			orgName =  os[2].substring(os[2].indexOf("(")+1, os[2].lastIndexOf(")"));
//        			claName = os[0];
//        			mName = os[1].substring(0, os[1].indexOf("("));
//        			
//        			// 构建方法，常量
//        			
//        			
//        		}else {
//        			claName = os[0];
//        			mName = os[1].substring(0, os[1].indexOf("("));
//        			((ExpressionStmt)valClintNode).setExpression(new NameExpr(Start.rpStr));
//        			
//        		}
//        		
//        		System.out.println("claName:" + claName + " mName:" + mName + " orgName:" + orgName);
//        		
//        	}
//        	
        	
        	
        	
        	
        	
     
        	
//        	List<Node> nodesList =  n.getChildrenNodes();
        	
//        	for (Node node :  nodesList){
//        		System.out.println("node:===========================");
//        		System.out.println("nodeCla:" + node.getClass());
//        		System.out.println("node:" + node);
//        		
//        	    if (node instanceof BlockStmt){
//                	for (Node nodeC :  node.getChildrenNodes()){
//                		System.out.println("nodeC:===========================");
//
//                		if (nodeC instanceof ClassOrInterfaceType){
//                    		System.out.println("nodeCCla:" + nodeC.getClass());
//                		}
//                		
//                		System.out.println("nodeC:" + nodeC);
//                		
////                		if (nodeC.toString().contains("new ")){
////                			Node node2 = getNameExpr(nodeC);
////                			((ExpressionStmt)nodeC).setExpression(new NameExpr("fdsafsdfsa"));
////                			
////                			System.out.println("=======getNameExpr:" + getNameExpr(nodeC));;
////                		}
//                		
//                		if (nodeC instanceof ExpressionStmt){
//                			
//                			if(nodeC.toString().contains("toString")){
//                				
//                				System.out.println(nodeC.contains(new NameExpr("list")));
//                				System.out.println(checkNameExpr(nodeC , new NameExpr("list")));
//                				
//                				MethodCallExpr nodee = (MethodCallExpr)nodeC.getChildrenNodes().get(0);
//                				System.out.println(nodee);
//                				nodee.setNameExpr(new NameExpr("aaa."));
//                				System.out.println(new NameExpr("list").equals(new NameExpr("list")));
//                				
////                				if (nodeC instanceof ExpressionStmt){
////                					((ExpressionStmt)nodeC).setExpression(new NameExpr("list.add('xiaoa')"));
////                				}
//                				
////                				Node node2 = nodeC.getChildrenNodes().get(0).getChildrenNodes().get(1);
////                				if (node2 instanceof ObjectCreationExpr){
////                					((ObjectCreationExpr)node2).setScope(new NameExpr("new LinkedList<>"));
////                				}else if (node2 instanceof StringLiteralExpr){
////									((StringLiteralExpr)node2).setValue("list.add(‘中国人’)");
////								}
////                    			;
////                        		System.out.println("ExpressionStmt:" + node2);
//                			}
//                			
//                			
//                    		
//
//                			
//                		}
//                		
//                	}
//                	
//
//        	    }
//        		
//
//        	}
        	
//        	System.out.println(n.getName());
        }
    }
    
    
    /**
     * 获取有关该变量代码
     * @param node
     * @param name
     * @return
     */
    public static List<MethodCallExpr> findMethodCallExpr(Node node, NameExpr name){
    	System.out.println(node);
    	List<MethodCallExpr> list = new ArrayList<>();
    	if (node instanceof MethodCallExpr && checkName1Expr(node , name)){
    		list.add((MethodCallExpr)node);
    	}else {
    		for(Node n : node.getChildrenNodes()){
    			list.addAll(findMethodCallExpr(n , name));
    		}
    	}
    	
    	return list;
    }
    
    
    public static NameExpr findName1Expr(Node node){
    	
    	if (node instanceof NameExpr){
    		return (NameExpr)node;
    	}
    	
     	for(Node n : node.getChildrenNodes()){
     		Node name = getNameExpr(n);
     		if (name != null) {
     			return (NameExpr)name;
			}
    		
    	}
     	
     	return null;
    }
    
    public static List<ExpressionStmt> findExpressionStmt(Node node){
    	
    	List<ExpressionStmt>  list = new ArrayList<>();
    	
    	if (node instanceof ExpressionStmt){
    		list.add((ExpressionStmt)node);
    	}else {
    		node.getChildrenNodes().forEach(e -> list.addAll(findExpressionStmt(e)));
    	}
    	
    	return list;
    	
    }
    
    
    
    public static NameExpr getNameExpr(Node node){
    	
    	if (node instanceof NameExpr){
    		return (NameExpr)node;
    	}
    	
     	for(Node n : node.getChildrenNodes()){
     		Node name = getNameExpr(n);
     		if (name != null) {
     			return (NameExpr)name;
			}
    		
    	}
     	
     	return null;
    }
    
    public static boolean checkNameExpr(Node node,NameExpr nameExpr){
    	if (node.contains(nameExpr)){
    		System.out.println("=nameExpr=======true");
    		return true;
    	}
    	
    	for(Node n : node.getChildrenNodes()){
    		if (checkNameExpr(n ,nameExpr)){
        		System.out.println("=checkNameExpr=======true");

    			return true;
    		}
    		
    	}
    	
    	return false;
    	
    }
    
    
    public static boolean checkName1Expr(Node node,NameExpr nameExpr){
    	if (node.equals(nameExpr)){
    		System.out.println("=nameExpr=======true");
    		return true;
    	}
    	
    	for(Node n : node.getChildrenNodes()){
    		if (n.equals(nameExpr)){
        		System.out.println("=checkNameExpr=======true");

    			return true;
    		}
    		
    	}
    	
    	return false;
    	
    }
    
    
    

}
